﻿using AiMoBridge.Interface;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace AiMoRhino.Pipeline
{
    /// <summary>
    /// 作为当前执行代码调用的Printer，使用Pipeline Server传输给对应的Client
    /// </summary>
    class PipePrinter : IDebugPrinter, IDisposable
    {
        readonly PipeServer pipe;
        static readonly double timeSpanSeconds = 0.2;
        static readonly int maxSendLine = 100;
        static readonly long timeSpanTick = TimeSpan.FromSeconds(timeSpanSeconds).Ticks;
        readonly BlockingCollection<string> printQueue = new BlockingCollection<string>();
        readonly Task printTask;
        readonly CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
        readonly List<string> batch = new List<string>();
        public PipePrinter(PipeServer pipe)
        {
            this.pipe = pipe;
            printTask = Task.Run(() => ProcessPrintQueue(cancellationTokenSource.Token));
        }
        public void SendRest()
        {
            if (batch.Count > 0)
            {
                string[] output = batch.ToArray();
                batch.Clear();
                PrintBatch(output);
            }
        }

        void ProcessPrintQueue(CancellationToken token)
        {
            try
            {
                DateTime lastSendTime = DateTime.Now;
                foreach (string content in printQueue.GetConsumingEnumerable(token))
                {
                    batch.Add(content);
                    DateTime now = DateTime.Now;
                    if ((now - lastSendTime).Ticks > timeSpanTick)
                    {
                        string[] output = batch.ToArray();
                        batch.Clear();
                        PrintBatch(output);
                        lastSendTime = now;
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // Handle the case when the operation is canceled
            }
        }

        void PrintBatch(string[] batch)
        {
            string content = "";
            if (batch.Length > maxSendLine)
            {
                batch = batch.Skip(batch.Length - maxSendLine).ToArray();
            }
            foreach (string text in batch)
            {
                content += "\r\n    " + text;
            }
            pipe.SendDebugText(content);
        }

        public void PrintDebug(string text)
        {
            printQueue.Add(text);
        }
        public void Dispose()
        {
            cancellationTokenSource.Cancel();
            printQueue.CompleteAdding();
            printTask.Wait();
            cancellationTokenSource.Dispose();
            printQueue.Dispose();
        }
    }
}
